package com.ruoyi.web.core.config

import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import com.ruoyi.common.config.RuoYiConfig
import io.swagger.annotations.ApiOperation
import io.swagger.models.auth.In
import springfox.documentation.builders.ApiInfoBuilder
import springfox.documentation.builders.PathSelectors
import springfox.documentation.builders.RequestHandlerSelectors
import springfox.documentation.service.ApiInfo
import springfox.documentation.service.ApiKey
import springfox.documentation.service.AuthorizationScope
import springfox.documentation.service.Contact
import springfox.documentation.service.SecurityReference
import springfox.documentation.service.SecurityScheme
import springfox.documentation.spi.DocumentationType
import springfox.documentation.spi.service.contexts.SecurityContext
import springfox.documentation.spring.web.plugins.Docket

/**
 * Swagger2的接口配置
 *
 * @author ruoyi
 */
@Configuration
open class SwaggerConfig {
    /** 系统基础配置  */
    @Autowired
    private lateinit var ruoyiConfig: RuoYiConfig

    /** 是否开启swagger  */
    @Value("\${swagger.enabled}")
    private val enabled = false

    /** 设置请求的统一前缀  */
    @Value("\${swagger.pathMapping}")
    private val pathMapping: String? = null

    /**
     * 创建API
     */
    @Bean
    open fun createRestApi(): Docket {
        return Docket(DocumentationType.OAS_30) // 是否启用Swagger
                .enable(enabled) // 用来创建该API的基本信息，展示在文档的页面中（自定义展示的信息）
                .apiInfo(apiInfo()) // 设置哪些接口暴露给Swagger展示
                .select() // 扫描所有有注解的api，用这种方式更灵活
                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation::class.java)) // 扫描指定包中的swagger注解
                // .apis(RequestHandlerSelectors.basePackage("com.ruoyi.project.tool.swagger"))
                // 扫描所有 .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.any())
                .build() /* 设置安全模式，swagger可以设置访问token */
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts())
                .pathMapping(pathMapping)
    }

    /**
     * 安全模式，这里指定token通过Authorization头请求头传递
     */
    private fun securitySchemes(): MutableList<SecurityScheme> {
        val apiKeyList: MutableList<SecurityScheme> = mutableListOf()
        apiKeyList.add(ApiKey("Authorization", "Authorization", In.HEADER.toValue()))
        return apiKeyList
    }

    /**
     * 安全上下文
     */
    private fun securityContexts(): MutableList<SecurityContext> {
        val securityContexts: MutableList<SecurityContext> = mutableListOf()
        securityContexts.add(
                SecurityContext.builder()
                        .securityReferences(defaultAuth())
                        .operationSelector { o -> o.requestMappingPattern().matches(Regex("/.*")) }
                        .build())
        return securityContexts
    }

    /**
     * 默认的安全上引用
     */
    private fun defaultAuth(): MutableList<SecurityReference> {
        val authorizationScope = AuthorizationScope("global", "accessEverything")
        val authorizationScopes: Array<AuthorizationScope?> = arrayOfNulls(1)
        authorizationScopes[0] = authorizationScope
        val securityReferences: MutableList<SecurityReference> = mutableListOf()
        securityReferences.add(SecurityReference("Authorization", authorizationScopes))
        return securityReferences
    }

    /**
     * 添加摘要信息
     */
    private fun apiInfo(): ApiInfo {
        // 用ApiInfoBuilder进行定制
        return ApiInfoBuilder() // 设置标题
                .title("标题：若依管理系统_接口文档") // 描述
                .description("描述：用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...") // 作者信息
                .contact(Contact(ruoyiConfig.name, null, null)) // 版本
                .version("版本号:" + ruoyiConfig.version)
                .build()
    }
}
